package com.missilike.biz.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.missilike.biz.*;
import com.missilike.core.domain.AccountInfoRequest;
import com.missilike.core.domain.AccountRegisteredReuqest;
import com.missilike.core.enums.SmsType;
import com.missilike.core.exception.BizException;
import com.missilike.core.result.BizResultCode;
import com.missilike.core.result.CommonResult;
import com.missilike.core.service.IIMService;
import com.missilike.core.service.impl.SmsService;
import com.missilike.core.utils.MD5Util;
import com.missilike.core.utils.ResultUtils;
import com.missilike.domain.mapper.MilAccountInfoMapper;
import com.missilike.domain.model.MilAccountDO;
import com.missilike.domain.request.MilAccountStatusForm;
import com.missilike.domain.response.AccountsFriendInfo;
import com.missilike.domain.response.MilAccountInfo;
import com.missilike.repository.entity.*;
import com.missilike.repository.entity.extend.MilAccountExtend;
import com.missilike.repository.mapper.MilAccountMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author kin
 * @since 2018-12-13
 */
@Slf4j
@Service
public class MilAccountServiceImpl extends ServiceImpl<MilAccountMapper, MilAccount> implements IMilAccountService {

    private final SmsService smsService;
    private final IIMService iimService;
    private final MilAccountThirdServiceImpl accountThirdService;
    private final IMilPhotoService photoService;
    private final IMilFriendRelationshipService friendRelationshipService;
    private final IMilFollowRelationshipService followRelationshipService;
    private final IMilFriendApplyService applyService;
    private final IMilContentCollectionService contentCollectionService;
    private final IMilAccountContentService accountContentService;
    private final IMilAccountAccessContentService milAccountAccessContentService;
    private final IMilContentTransmitService milContentTransmitService;

    @Autowired
    public MilAccountServiceImpl(SmsService smsService, IIMService iimService, MilAccountThirdServiceImpl accountThirdService,
                                 IMilPhotoService photoService, IMilFriendRelationshipService friendRelationshipService,
                                 IMilFollowRelationshipService followRelationshipService, IMilFriendApplyService applyService,
                                 IMilContentCollectionService contentCollectionService, IMilAccountContentService accountContentService,
                                 IMilAccountAccessContentService milAccountAccessContentService,IMilContentTransmitService milContentTransmitService) {
        this.smsService = smsService;
        this.iimService = iimService;
        this.accountThirdService = accountThirdService;
        this.photoService = photoService;
        this.friendRelationshipService = friendRelationshipService;
        this.followRelationshipService = followRelationshipService;
        this.applyService = applyService;
        this.contentCollectionService = contentCollectionService;
        this.accountContentService = accountContentService;
        this.milAccountAccessContentService=milAccountAccessContentService;
        this.milContentTransmitService=milContentTransmitService;
    }


    @PostConstruct
    public void init() {
        friendRelationshipService.setAccountService(this);
        followRelationshipService.setFollowRelationshipService(this);
        applyService.setFriendApplyService(this);
        accountContentService.setAccountService(this);
        accountContentService.setCollectionService(this.contentCollectionService);
        applyService.setFriendRelationshipService(this.friendRelationshipService);
    }


    @Override
    public MilAccount login(Long account, String password, String smsCode, String phoneNumber) {
        MilAccount milAccount = null;
        //短信登陆 or  账号密码登陆
        if (StringUtils.isNoneBlank(smsCode)) {
            milAccount = handleMilAccount(phoneNumber, smsCode, SmsType.LOGIN);
        } else {
            //账号密码
            milAccount = baseMapper.queryUser(MD5Util.encoder(password), account, phoneNumber);
            if (milAccount == null) {
                throw new BizException(BizResultCode.ACCOUNT_PASSWORD_ERROR);
            }
        }
        milAccount.setPassword(null);
        return milAccount;
    }

    @Override
    public MilAccount userRegistered(AccountRegisteredReuqest reuqest) {
        MilAccount milAccount = getOne(new QueryWrapper<MilAccount>().lambda().eq(MilAccount::getPhone, reuqest.getPhoneNumber()));
        if (milAccount != null) {
            throw new BizException(BizResultCode.ACCOUNT_ALREADY_XIST);
        }
        //校验验证码
        if (smsService.verificationCode(reuqest.getPhoneNumber(), reuqest.getSmsCode(), SmsType.REGISTER)) {
            milAccount = MilAccountInfoMapper.MAPPER.formDO(new MilAccountDO(MD5Util.encoder(reuqest.getPassword()), reuqest.getPhoneNumber(), reuqest.getDeviceCode()));
            baseMapper.insertMilAccount(milAccount);
            //todo faceurl
            String faceUrl = null;
            if (milAccount.getFaceUrlId() != null && milAccount.getFaceUrlId() > 0) {
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.lambda().eq("id", milAccount.getFaceUrlId());
                faceUrl = baseMapper.selectObjs(queryWrapper).toString();
            }
            iimService.exportNormalAccountToIM(milAccount.getAccount(), milAccount.getNickName(), faceUrl);
            if (StringUtils.isNoneBlank(reuqest.getThirdId())) {
                MilAccountThird milAccountThird = new MilAccountThird();
                milAccountThird.setAccountThirdId(milAccount.getId());
                milAccountThird.setAccountThirdType(reuqest.getThirdType());
                milAccountThird.setMilAccountId(milAccount.getId());
                accountThirdService.save(milAccountThird);
            }
            milAccount.setPassword(null);
            return milAccount;
        }
        return null;
    }

    @Override
    public MilAccount accountPsdResetService(String phoneNumber, String smsCode, String newPassword) {
        MilAccount milAccount = handleMilAccount(phoneNumber, smsCode, SmsType.RESET);
        milAccount.setPassword(MD5Util.encoder(newPassword));
        baseMapper.update(milAccount, new QueryWrapper<MilAccount>().lambda().eq(MilAccount::getId, milAccount.getId()));
        milAccount.setPassword(null);
        return milAccount;
    }

    @Override
    public Page<MilAccountInfo> getList(Page<MilAccount> page, String account) {
        IPage<MilAccount> milAccountIPage = baseMapper.selectPage(page, new QueryWrapper<MilAccount>()
                .lambda()
                .likeRight(MilAccount::getAccount, account)
        );
        return MilAccountInfoMapper.MAPPER.pageConvert(milAccountIPage);
    }

    @Override
    public MilAccountInfo getAccount(String accountId) {
        MilAccount account = this.getById(accountId);
        if (account == null) {
            throw new BizException(BizResultCode.NO_ACCOUNT);
        }
        MilAccountInfo info = MilAccountInfoMapper.MAPPER.toInfo(account);

        if (info.getFaceUrlId() != null && info.getFaceUrlId() > 0) {
            info.setFaceUrl(photoService.getPhotoUrl(info.getFaceUrlId()));
        }
        if (info.getBackGroundPhotoId() != null && info.getBackGroundPhotoId() > 0) {
            info.setBackGroundPhotoUrl(photoService.getPhotoUrl(info.getBackGroundPhotoId()));
        }
        return info;
    }

    @Override
    public void status(MilAccountStatusForm milAccountStatusForm) {
        if (milAccountStatusForm.getStatus() == 3) {
            baseMapper.updateStatusByIds(milAccountStatusForm.getAccountIds());
        } else {
            MilAccount account = new MilAccount();
            account.setStatus(milAccountStatusForm.getStatus());
            baseMapper.update(account, new UpdateWrapper<MilAccount>()
                    .lambda()
                    .in(MilAccount::getId, Arrays.asList(milAccountStatusForm.getAccountIds()))
            );
        }
    }

    @Override
    public MilAccount updateAccountInfo(AccountInfoRequest request) {
        if (null == request) {
            return null;
        }

        MilAccount account = baseMapper.selectById(request.getId());
        if (request.getFaceUrlId() != null && request.getFaceUrlId() > 0) {
            account.setFaceUrlId(request.getFaceUrlId());
        }

        if (request.getBackGroundPhotoId() != null && request.getBackGroundPhotoId() > 0) {
            account.setBackGroundPhotoId(request.getBackGroundPhotoId());
        }

        if (!StringUtils.isBlank(request.getCity())) {
            account.setLocationCity(request.getCity());
        }

        if (!StringUtils.isBlank(request.getLocationDetail())) {
            account.setLocationDetail(request.getLocationDetail());
        }


        if (!StringUtils.isBlank(request.getNickName())) {
            account.setNickName(request.getNickName());
        }

        if (!StringUtils.isBlank(request.getAlipayAccount())) {
            account.setAlipayAccount(request.getAlipayAccount());
        }

        if (!StringUtils.isBlank(request.getAlipayName())) {
            account.setAlipayName(request.getAlipayAccount());
        }


        if (request.getRewardIncrease() != null) {
            account.setRewardIncrease(request.getRewardIncrease());
        }

        if (!StringUtils.isBlank(request.getIdentificationCode())) {
            account.setIdentificationCode(request.getIdentificationCode());
        }

        if (!StringUtils.isBlank(request.getEmail())) {
            account.setEmail(request.getEmail());
        }

        if (request.getGender() != null) {
            account.setGender(request.getGender());
        }


        baseMapper.updateById(account);


        if (account.getFaceUrlId() != null && account.getFaceUrlId() > 0) {
            MilPhoto photo = photoService.getById(account.getFaceUrlId());
            iimService.exportNormalAccountToIM(account.getAccount(), account.getNickName(), photo.getPhotoUrl());
        }
        return account;
    }

    @Override
    public List<MilAccountInfo> getTopUser() {
        List<MilAccount> topUserList = this.baseMapper.selectTopUser();
        return MilAccountInfoMapper.MAPPER.toList(topUserList);
    }

    @Override
    public List<MilAccountExtend> getUserByCondition(String id, String userAccount, String nickName, String mobile) {
        List<MilAccountExtend> users = new ArrayList<>();
        LambdaQueryWrapper<MilAccount> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNoneBlank(userAccount)) {
            queryWrapper.eq(MilAccount::getAccount, userAccount);
        }
        if (StringUtils.isNoneBlank(nickName)) {
            queryWrapper.or().like(MilAccount::getNickName, nickName);
        }
        if (StringUtils.isNoneBlank(mobile)) {
            queryWrapper.or().eq(MilAccount::getPhone, mobile);
        }
        List<MilAccount> accounts = baseMapper.selectList(queryWrapper);

        for (MilAccount account : accounts) {
            if (account.getId().equals(id)) {
                continue;
            }
            MilAccountExtend user = new MilAccountExtend();
            BeanUtils.copyProperties(account, user);
            if (account.getFaceUrlId() != null && account.getFaceUrlId() > 0) {
                user.setFaceUrl(photoService.getPhotoUrl(account.getFaceUrlId()));
            }

            if (friendRelationshipService.isFriend(id, account.getId())) {
                user.setFriendRelatationType(1);
            } else if (applyService.inApply(id, account.getId())) {
                user.setFriendRelatationType(2);
            } else {
                user.setFriendRelatationType(0);
            }

            if (followRelationshipService.isAFollowB(account.getId(), id)) {
                user.setFlollowRelatationType(1);
            }
            users.add(user);
        }
        users.forEach(item -> {
            item.setPassword(null);
        });
        return users;
    }

    @Override
    public List<MilAccountExtend> getUserByCondition(String id, String keyWord) {
        return getUserByCondition(id, keyWord, keyWord, keyWord);
    }


    private MilAccount handleMilAccount(String phoneNumber, String smsCode, SmsType smsType) {
        MilAccount milAccount = getOne(new QueryWrapper<MilAccount>().lambda().eq(MilAccount::getPhone, phoneNumber));
        if (milAccount == null) {
            throw new BizException(BizResultCode.NO_ACCOUNT);
        }
        if (StringUtils.isNoneBlank(smsCode)) {
            smsService.verificationCode(phoneNumber, smsCode, smsType);
        }
        return milAccount;
    }


    @Override
    public List<MilAccountInfo> getUserByIds(Set<String> ids) {
        QueryWrapper<MilAccount> milAccountQueryWrapper = new QueryWrapper<>();
        milAccountQueryWrapper.lambda().in(MilAccount::getId, ids);
        List<MilAccount> accounts = baseMapper.selectList(milAccountQueryWrapper);
        List<MilAccountInfo> infos = MilAccountInfoMapper.MAPPER.toList(accounts);
        for (MilAccountInfo info : infos) {
            if (info.getFaceUrlId() != null && info.getFaceUrlId() > 0) {
                info.setFaceUrl(photoService.getPhotoUrl(info.getFaceUrlId()));
            }
            if (info.getBackGroundPhotoId() != null && info.getBackGroundPhotoId() > 0) {
                info.setBackGroundPhotoUrl(photoService.getPhotoUrl(info.getBackGroundPhotoId()));
            }
            info.setBeFollowed(followRelationshipService.getBeFollowedCount(info.getId()));
            info.setBeCollection(contentCollectionService.getUserBeCollectionCount(info.getId()));
            info.setCollection(contentCollectionService.getUserCollectionCount(info.getId()));
            info.setContented(accountContentService.getAccountContentCount(info.getId()));
        }
        return infos;
    }

    @Override
    public void resetDisableUser() {
        List<String> accountIds = baseMapper.selectResetAccountId();
        log.info("reset disable user count:%s", CollectionUtils.size(accountIds));
        int update = baseMapper.update(new MilAccount(), new UpdateWrapper<MilAccount>().lambda()
                .set(MilAccount::getStatus, 1)
                .set(MilAccount::getBanTime, null)
                .in(MilAccount::getId, accountIds)
        );
        log.info("reset disable user success count:%s", update);
    }

    @Override
    public void changeBalance(String accountId, BigDecimal amount){
        MilAccount milAccount = getOne(new QueryWrapper<MilAccount>().lambda().eq(MilAccount::getId, accountId));
        if (milAccount == null) {
            throw new BizException(BizResultCode.ACCOUNT_ALREADY_XIST);
        }
        BigDecimal balance = milAccount.getBalance();
        BigDecimal total = balance.add(amount);
        milAccount.setBalance(total);
        this.updateById(milAccount);
    }

    @Override
    public void setEquipmentService(IMilEquipmentService iMilEquipmentService) {
        applyService.setEquipmentService(iMilEquipmentService);
    }

    public CommonResult updataExperience(String accountId, Integer experience) {
        if (experience == null || experience == 0) {
            throw new BizException(BizResultCode.EXPERIENCE_NOT_NULL);
        }
        MilAccount milAccount = getOne(new QueryWrapper<MilAccount>().lambda().eq(MilAccount::getId, accountId));
        if (milAccount == null) {
            throw new BizException(BizResultCode.ACCOUNT_ALREADY_XIST);
        }
        Integer nextLevelExperience = 0;
        if (milAccount.getAccountLevel() == 0) {
            nextLevelExperience = 11;
        } else {
            nextLevelExperience = milAccount.getAccountLevel() * milAccount.getAccountLevel() * 11;
        }
        if (milAccount.getExperience() + experience >= nextLevelExperience) {//升级
            milAccount.setAccountLevel(milAccount.getAccountLevel() + 1);
            nextLevelExperience = milAccount.getAccountLevel() * milAccount.getAccountLevel() * 11;//下一等级需要多少分
        }
        milAccount.setExperience(milAccount.getExperience() + experience);
        milAccount.setNextLevel(nextLevelExperience - milAccount.getExperience());
        this.updateById(milAccount);
        return ResultUtils.ok();

    }

    public AccountsFriendInfo getAccountsFriendInfo(String accountId){
        AccountsFriendInfo info=new AccountsFriendInfo();
        //图文
        //长文
        QueryWrapper<MilAccountAccessContent> rewardRecordQueryWrapper = new QueryWrapper<>();
        rewardRecordQueryWrapper.lambda().eq(MilAccountAccessContent::getAccountId, "836bf167-a1e8-4597-be2a-31a57c888e4d");
        List<MilAccountAccessContent> rewardRecords = milAccountAccessContentService.list(rewardRecordQueryWrapper);
        Map<Integer,List<MilAccountAccessContent>> map= rewardRecords.stream().collect(Collectors.groupingBy(MilAccountAccessContent::getMilAccountContentType));
        for (Map.Entry<Integer, List<MilAccountAccessContent>> entry : map.entrySet()) {
            switch (entry.getKey()){
                case 1:info.setPictureCount(map.get(entry.getKey())!=null?map.get(entry.getKey()).size():0);continue;
                case 2:info.setArticleCount(map.get(entry.getKey())!=null?map.get(entry.getKey()).size():0);continue;
            }
        }
        info.setBrowseCount(info.getPictureCount()+info.getArticleCount());
        //点赞
        QueryWrapper<MilContentTransmit> milContentTransmitQueryWrapper = new QueryWrapper<>();
        milContentTransmitQueryWrapper.lambda().eq(MilContentTransmit::getAccountId, "836bf167-a1e8-4597-be2a-31a57c888e4d");
        info.setPraiseCount(milContentTransmitService.list(milContentTransmitQueryWrapper).size());
        //收藏
        QueryWrapper<MilContentCollection> milContentCollectionQueryWrapper = new QueryWrapper<>();
        milContentCollectionQueryWrapper.lambda().eq(MilContentCollection::getAccountId, "836bf167-a1e8-4597-be2a-31a57c888e4d");
        info.setCollectCount(contentCollectionService.list(milContentCollectionQueryWrapper).size());
        return info;
    }

}
